<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图形缩放</title>
</head>
<link href="../../css/joint.css" rel="stylesheet"/>
<link href="../../css/paper.css" rel="stylesheet"/>
<body>

<!--画布-->
<div id="paper"></div>

<script src="../../js/jquery.js"></script>
<script src="../../js/lodash.js"></script>
<script src="../../js/backbone.js"></script>
<script src="../../js/joint.js"></script>

<script>
    class ResizeControl{
        parentBbox=null;
        paper=null;
        resizeElement=null;
        bindElement=null;
        Resize = joint.dia.Element.define('custom.Resize', {
            markup: [{
                tagName: 'rect',
                selector: 'body'
            },{
                tagName: 'rect',
                selector: 'topLeft'
            },{
                tagName: 'rect',
                selector: 'topRight'
            },{
                tagName: 'rect',
                selector: 'bottomLeft'
            },{
                tagName: 'rect',
                selector: 'bottomRight'
            }],
            attrs: {
                body: {
                    opacity:'0',
                    stroke: '#000',
                    refWidth: '100%',
                    refHeight: '100%'
                },
                topLeft: {
                    fill: '#fff',
                    stroke: '#000',
                    x:-3,
                    y:-3,
                    width: 7,
                    height: 7,
                    event: 'resize:topLeft',
                    cursor: 'nwse-resize'
                },
                topRight: {
                    fill: '#fff',
                    stroke: '#000',
                    refX: '100%',
                    x:-3,
                    y:-3,
                    width: 7,
                    height: 7,
                    event: 'resize:topRight',
                    cursor: 'nesw-resize'
                },
                bottomLeft: {
                    fill: '#fff',
                    stroke: '#000',
                    refY: '100%',
                    x:-3,
                    y:-3,
                    width: 7,
                    height: 7,
                    event: 'resize:bottomLeft',
                    cursor: 'nesw-resize'
                },
                bottomRight: {
                    fill: '#fff',
                    stroke: '#000',
                    refX: '100%',
                    refY: '100%',
                    x:-3,
                    y:-3,
                    width: 7,
                    height: 7,
                    event: 'resize:bottomRight',
                    cursor: 'nwse-resize'
                },
            }
        });

        constructor(paper){
            this.paper=paper;
            var that=this;

            //事件响应
            paper.on('resize:topLeft', function(elementView, evt) {
                evt.stopPropagation();
                that.drag(evt.offsetX,evt.offsetY,1,1,-1,-1);
            });
            paper.on('resize:bottomRight', function(elementView, evt) {
                evt.stopPropagation();
                that.drag(evt.offsetX,evt.offsetY,0,0,1,1);
            });
            paper.on('resize:topRight', function(elementView, evt) {
                evt.stopPropagation();
                that.drag(evt.offsetX,evt.offsetY,0,1,1,-1);
            });
            paper.on('resize:bottomLeft', function(elementView, evt) {
                evt.stopPropagation();
                that.drag(evt.offsetX,evt.offsetY,1,0,-1,1);
            });

            paper.on('element:pointerclick', function(cellView, evt,x,y) {
                evt.stopPropagation();

                that.bind(cellView.model);
            });
            paper.on('blank:pointerclick', function(evt,x,y) {
                that.unbind();
            });
            paper.on('element:mouseenter', function(cellView,evt) {
                cellView.model.attr('body/fill-opacity','0.1');
            });
            paper.on('element:mouseleave', function(cellView,evt) {
                cellView.model.attr('body/fill-opacity','1');
            });

            this.parentBbox = g.Rect(0,0,paper.options.width,paper.options.height);
            paper.model.on('change:position', function(cell) {
                //边界检查，确保元素不被移动到边界外
                var cellBbox = cell.getBBox();

                if (that.parentBbox.containsPoint(cellBbox.origin()) &&
                    that.parentBbox.containsPoint(cellBbox.topRight()) &&
                    that.parentBbox.containsPoint(cellBbox.corner()) &&
                    that.parentBbox.containsPoint(cellBbox.bottomLeft())) {

                    // All the four corners of the child are inside
                    // the parent area.
                    return;
                }

                // Revert the child position.
                cell.set('position', cell.previous('position'));
            });

        }
        //绑定元素
        bind(element){
            //如果点击自己，则返回
            if(element.attributes.type=='custom.Resize') return;
            //释放上一个绑定
            this.unbind();

            //绑定元素
            this.bindElement=element;
            var that=this;
            this.resizeElement = (new this.Resize())
                .size(element.attributes.size.width,element.attributes.size.height)
                .position(element.attributes.position.x,element.attributes.position.y)
                .addTo(this.paper.model);

            //让绑定元素位置和大小同步
            this.resizeElement.on('change:position', function(element, position) {
                that.bindElement.position(position.x,position.y);
            });
            this.resizeElement.on('change:size', function(element, size) {
                that.bindElement.resize(size.width,size.height);
            });
        }
        //拖动元素尺寸
        drag(startX,startY,xDir,yDir,wDir,hDir){
            var that=this;
            //记录初始坐标
            var elementX=this.resizeElement.attributes.position.x;
            var elementY=this.resizeElement.attributes.position.y;

            const MIN_SIZE=15;//最小尺寸
            var elementWidth=this.resizeElement.attributes.size.width;
            var elementHeight=this.resizeElement.attributes.size.height;
            $(this.paper.el).bind('mousemove',function(event) {
                //计算移动量
                var dx=event.offsetX - startX;
                var dy=event.offsetY - startY

                //计算新坐标
                var newX=elementX + dx*xDir;
                var newY=elementY + dy*yDir;
                newX=(elementX+elementWidth)-newX>=MIN_SIZE?newX:(elementX+elementWidth)-MIN_SIZE,
                    newY=(elementY+elementHeight)-newY>=MIN_SIZE?newY:(elementY+elementHeight)-MIN_SIZE;

                //计算新尺寸
                var newWidth=elementWidth + dx*wDir;
                var newHeight=elementHeight + dy*hDir;
                newWidth=newWidth>=MIN_SIZE?newWidth:MIN_SIZE,
                    newHeight=newHeight>=MIN_SIZE?newHeight:MIN_SIZE;

                //移动元素
                that.resizeElement.position(newX,newY);
                that.resizeElement.resize(newWidth,newHeight);
            });
            $("body").bind('mouseup',function(event) {
                $(that.paper.el).unbind('mousemove');
                $("body").unbind('mouseup');
            });
        }
        //释放元素
        unbind(){
            if(this.resizeElement){
                this.resizeElement.remove();
                this.resizeElement=null;
            }
        }
    }
</script>

<script type="text/javascript">

    var graph = new joint.dia.Graph;

    var paper = new joint.dia.Paper({
        el: document.getElementById('paper'),
        model: graph,
        width: 600,
        height: 500,
        gridSize: 1,
        //background:{
        //	image:'./2019-02-15_115055.png'
        //}
    });

    var resizeControl=new ResizeControl(paper);

    var ellipse = new joint.shapes.standard.Ellipse();
    ellipse.resize(150, 100);
    ellipse.position(425, 10);
    ellipse.attr('root/title', 'joint.shapes.standard.Ellipse');
    ellipse.attr('label/text', 'Ellipse');
    ellipse.attr('body/fill', 'lightblue');
    ellipse.attr('body/fill-opacity','0');
    ellipse.attr('body/stroke','red');

    ellipse.addTo(graph);

    var circle = new joint.shapes.standard.Circle();
    circle.resize(100, 100);
    circle.position(250, 10);
    circle.attr('root/title', 'joint.shapes.standard.Circle');
    circle.attr('label/text', 'Circle');
    circle.attr('body/fill', 'lightblue');
    circle.addTo(graph);

    var rect = new joint.shapes.standard.Rectangle();
    rect.position(100, 30);
    rect.resize(100, 40);
    rect.attr({
        body: {
            fill: 'blue'
        },
        label: {
            text: 'Hello',
            fill: 'white'
        }
    });
    rect.addTo(graph);

    var rect2 = rect.clone();
    rect2.translate(300, 0);
    rect2.attr('label/text', 'World!');
    rect2.addTo(graph);

    var link = new joint.shapes.standard.Link();
    link.source(rect);
    link.target(rect2);
    link.addTo(graph);

</script>

</body>
</html>